Skip to content
View Article Network

Elasticsearch QueryString Query Syntax Notes

I recently started storing logs in Elasticsearch, but doing so requires a convenient UI for querying. For me, Kibana is too complex, and querying via Postman is cumbersome. I discovered a tool called Elasticvue, which I chose because it supports various browser extensions and desktop application versions.

The query interface for Elasticvue is primarily based on the query_string syntax, which is an extended version of the Lucene query syntax in Elasticsearch. For users familiar with SQL, query_string is easier to pick up than other DSL syntaxes, so I have compiled some commonly used syntax for quick reference.

You can check the Elasticvue official website for various browser extensions or installation files/links for the desktop application.

Test version: Elasticsearch 9.1.4

Basic Syntax

Basic API Structure

json
{
  "query": {
    "query_string": {
      "query": "your query string here",     // Required parameter: query string (use "*" to search all documents)
      "default_field": "content",            // Optional parameter: default search field; if not specified, defaults to "*", searching all fields
      "default_operator": "OR"               // Optional parameter: default operator, defaults to OR
      // Other optional parameters
    }
  },
  "size": 10,                                // Optional parameter: number of results to return, defaults to 10
  "from": 0,                                 // Optional parameter: starting position, defaults to 0
  "sort": []                                 // Optional parameter: result sorting
}

When no field is specified, QueryString searches across all searchable fields.

Query Syntax

Simple keyword search:

text
apple

Multiple terms (defaults to connecting with OR):

text
apple banana

Search Behavior for Different Field Types

Elasticsearch uses different analysis strategies for different field types (official documentation):

  • text fields: Use the standard analyzer, which tokenizes and converts to lowercase.
  • keyword fields: Use the keyword analyzer, keeping the complete string unchanged.
  • Numeric/Date/Boolean fields: Do not use an analyzer; they index the raw value.
  • query_string: Processes the query string according to the strategy corresponding to the target field type.
Field TypeQuery StringBehavior Description
textapple bananaEquivalent to apple OR banana, matches if either term is found
keyword"apple" "banana"Must use double quotes to explicitly search for multiple complete strings, or use apple OR banana
keywordapple bananaNo results, as it is treated as a single complete string match
Numeric/Date/Boolean"123" "456"Multi-value search must explicitly specify values using double quotes, or use 123 OR 456
Numeric/Date/Boolean123 456No results, as query_string does not automatically split multiple complete values

JSON multi-term query example (using escaped double quotes):

json
{
  "query": {
    "query_string": {
      "query": "\"apple\" \"banana\""
    }
  }
}

Exact phrase search (using double quotes):

text
"red apple"

2. Boolean Operators

AND operator (both terms must exist):

text
apple AND banana

OR operator (at least one term must exist):

text
apple OR banana

NOT operator (excludes documents containing a term):

text
apple NOT banana

Plus sign (must include this term):

text
+apple banana

Minus sign (must exclude this term):

text
apple -banana

WARNING

English operators must be in all caps.

3. Field-Specific Query

Search for a specific field:

text
title:apple

Query for multiple fields:

text
title:apple AND content:banana

Multi-value query (OR condition):

text
user_id:(1234 OR 5678)

Field existence query:

text
_exists_:email        // Query documents where the email field exists; can be understood as not null
NOT _exists_:phone    // Query documents where the phone field does not exist; can be understood as null

Field specification priority: Explicitly specified field in query string > fields parameter > default_field parameter.

4. Range Queries and Comparison Operators

Range Queries:

text
price:[10 TO 20]    // Closed interval, includes 10 and 20
price:{10 TO 20}    // Open interval, excludes 10 and 20
price:[10 TO *]     // Greater than or equal to 10
price:[* TO 20]     // Less than or equal to 20

Comparison Operators:

text
price:>10           // Greater than 10
price:>=10          // Greater than or equal to 10
price:<20           // Less than 20
price:<=20          // Less than or equal to 20

These two writing styles are functionally similar; you can choose based on the context. However, testing shows that range query syntax has better compatibility across various parameter combinations. Below are test examples:

Limitations on using comparison operators:

Comparison operators (>, >=, <, <=) cause errors when used with the fields array parameter, but work correctly when using default_field or specifying the field directly in the query string.

Working syntax:

json
// Method 1: No field specified
{
  "query": {
    "query_string": {
      "query": ">=10"
    }
  }
}

// Method 2: Specify field in query string
{
  "query": {
    "query_string": {
      "query": "price:>=10"
    }
  }
}

// Method 3: Use default_field parameter
{
  "query": {
    "query_string": {
      "query": ">=10",
      "default_field": "price"
    }
  }
}

Syntax that causes errors:

json
// Using the fields array causes the query to fail
{
  "query": {
    "query_string": {
      "query": ">=10",
      "fields": ["price"]
    }
  }
}

Solution: Use range query syntax instead

Range query syntax ([x TO y]) is compatible with the fields parameter and works correctly:

json
{
  "query": {
    "query_string": {
      "query": "[10 TO *]",
      "fields": ["price"]
    }
  }
}

Wildcard search:

text
te?t      // Question mark represents a single character
test*     // Asterisk represents zero or more characters

6. Date and Time Query

Basic Date Range Query

Use range syntax for date queries:

text
timestamp:[2023-01-01 TO 2023-01-31]

You can also use relative time for queries:

text
timestamp:>now-1d  // Query data from the past 24 hours

Common relative time expressions:

  • now-1h: One hour ago
  • now-1d: One day ago
  • now-1w: One week ago
  • now/d: Start of today (00:00:00)
  • now/w: Start of this week
  • now/M: Start of this month

Date and Time Format

The Elasticsearch date type defaults to millisecond precision; if nanosecond precision is needed, use the date_nanos type.

Supported formats:

  • Standard format: yyyy-MM-ddTHH:mm:ss.SSSZ (e.g., 2023-01-15T08:30:00.000Z)
  • Simplified format: yyyy-MM-dd (e.g., 2023-01-15)
  • Default timezone is UTC.

Format behavior differences:

Different date format precisions have different behaviors during queries. Here are the key differences:

json
// When querying by "year", it precisely matches the first second of that year
{
  "query": {
    "query_string": {
      "query": "timestamp:2023"  // Equivalent to ="2023-01-01T00:00:00Z"
    }
  }
}

// When querying by "month", it precisely matches the first second of that month
{
  "query": {
    "query_string": {
      "query": "timestamp:2023-02"  // Equivalent to ="2023-02-01T00:00:00Z"
    }
  }
}

// When precision reaches "day", behavior changes
// This queries the entire range of that date
{
  "query": {
    "query_string": {
      "query": "timestamp:2023-03-01"  // Queries >="2023-03-01T00:00:00Z" <"2023-03-02T00:00:00Z"
    }
  }
}

// When precision reaches "hour", it queries the entire range of that hour
{
  "query": {
    "query_string": {
      "query": "timestamp:2023-03-01T08"  // Queries >="2023-03-01T08:00:00Z" <"2023-03-01T09:00:00Z"
    }
  }
}

// When precision reaches "minute", double quotes are required (because it contains a colon)
{
  "query": {
    "query_string": {
      "query": "timestamp:\"2023-03-01T08:00\""  // Queries >="2023-03-01T08:00:00Z" <"2023-03-01T08:01:00Z"
    }
  }
}

Usage Notes

1. Standard format requires double quotes

Because the standard format contains a colon :, it is treated as a special character in QueryString and must be enclosed in double quotes:

Incorrect syntax (causes parsing error):

json
{
  "query": {
    "query_string": {
      "query": "timestamp:2023-01-15T08:30:00Z"
    }
  }
}

Correct syntax:

json
// Method 1: Enclose in double quotes
{
  "query": {
    "query_string": {
      "query": "timestamp:\"2023-01-15T08:30:00Z\""
    }
  }
}

// Method 2: Use simplified format (no colon)
{
  "query": {
    "query_string": {
      "query": "timestamp:2023-01-15"
    }
  }
}

2. Date queries do not support comparison operators

When using comparison operators to query dates, the query will fail or produce an error:

json
// This query actually searches for data matching that date in "all fields"
// instead of performing a comparison in the timestamp field
{
  "query": {
    "query_string": {
      "query": "timestamp:>=\"2023-01-15T08:30:00Z\""
    }
  }
}

// If you switch to default_field or fields, it will directly cause a parsing error
{
  "query": {
    "query_string": {
      "query": ">=\"2023-01-15T08:30:00Z\"",
      "fields": ["timestamp"]  // ❌ Will report an error
    }
  }
}

{
  "query": {
    "query_string": {
      "query": ">=\"2023-01-15T08:30:00Z\"",
      "default_field": "timestamp"  // ❌ Will report an error
    }
  }
}

Correct approach: Use range query syntax

json
{
  "query": {
    "query_string": {
      "query": "timestamp:[2023-01-15T08:30:00Z TO *]"
    }
  }
}

3. Impact of custom formats

When a date type field has a specified format (other than the default strict_date_optional_time||epoch_millis), the query format must exactly match the specified format:

json
// Assuming the field is defined as follows
"timestamp": {
    "type": "date",
    "format": "yyyy-MM-dd'T'HH:mm:ss'Z'"
}

Using the wrong format leads to different results:

json
// Specifying the field directly in the query: No results (silent failure)
{
  "query": {
    "query_string": {
      "query": "timestamp:[2023-01-15T08:30 TO *]"  // Format mismatch
    }
  }
}

// Using default_field or fields: Produces an error message
{
  "query": {
    "query_string": {
      "query": "[2023-01-15T08:30 TO *]",
      "default_field": "timestamp"  // Will report error: failed to parse date field
    }
  }
}

Error message example:

text
failed to parse date field [2023-01-15T08:30] with format [yyyy-MM-dd'T'HH:mm:ss'Z']

Other Parameters

default_field vs fields:

  • default_field: Specifies a single field for default searching.
  • fields: Specifies multiple search fields and their weights.
json
// Using default_field
{
  "query_string": {
    "query": "apple",
    "default_field": "content"
  }
}

// Using fields
{
  "query_string": {
    "query": "apple",
    "fields": ["title^2", "content", "tags"]
  }
}

2. analyzer

Specifies how query_string processes and analyzes the query string. Elasticsearch provides various built-in analyzers; for a detailed list, refer to the official documentation.

json
{
  "query_string": {
    "query": "The Quick Brown Fox",
    "analyzer": "standard"
  }
}

Important Concept: Index-time vs. Query-time Analyzers

Elasticsearch uses analyzers at two stages:

1. Index-time Analyzer

  • Processes data being stored in the index.
  • Example: text field stores "Wing Chou" → tokenized as ["wing", "chou"].

2. Query-time Analyzer

  • Processes the query string.
  • The analyzer parameter of query_string controls this stage.

Example Explanation

Assuming the text field has stored "Wing Chou", and index-time tokenization is ["wing", "chou"]:

json
// ✅ Using standard analyzer
// Query string is analyzed as ["wing", "chou"], and the default operator is OR, so it matches the data regardless of whether it's wing or chou
{
  "query_string": {
    "query": "Wing Chou",
    "analyzer": "standard"
  }
}

// ❌ Using keyword analyzer, incorrect query condition
// Query string remains the complete "Wing Chou", cannot match the tokenized result
{
  "query_string": {
    "query": "Wing Chou",
    "analyzer": "keyword"
  }
}

// Query string remains "Wing" (uppercase), cannot match "wing" (lowercase) in the data
{
  "query_string": {
    "query": "Wing",
    "analyzer": "keyword"
  }
}

// ✅ Using keyword analyzer, correct query condition
{
  "query_string": {
    "query": "wing",
    "analyzer": "keyword"
  }
}

{
  "query_string": {
    "query": "wing OR chou",
    "analyzer": "keyword"
  }
}

3. analyze_wildcard

Controls whether wildcard expressions are analyzed. The official documentation states:

(Optional parameter, boolean) If set to true, the query will attempt to analyze wildcard terms. Defaults to false.

Note that even if set to true, only queries ending in * will be fully analyzed. Queries starting with or containing * in the middle will only be normalized.

json
{
  "query_string": {
    "query": "Te*",
    "analyze_wildcard": true,
    "analyzer": "standard"
  }
}

Parameter Value Explanation

  • analyze_wildcard: false (default): Wildcard expressions are not processed by the analyzer.
  • analyze_wildcard: true: Wildcard expressions are processed by the analyzer, but the processing method depends on the wildcard position:
    • Trailing wildcard (e.g., Te*): Fully analyzed.
    • Leading or middle wildcard (e.g., *Te*, T*e): Only normalized.

Observations and Questions from Testing

In actual testing, I found that the behavior of this parameter has some inconsistencies or is difficult to understand compared to the official documentation:

1. Behavior of Text fields

Regardless of whether analyze_wildcard is set to true or false, the query is case-insensitive:

json
// The results of the following two queries are the same, both matching the data
{
  "query_string": {
    "query": "name:Te*",
    "analyze_wildcard": true
  }
}

{
  "query_string": {
    "query": "name:Te*",
    "analyze_wildcard": false
  }
}

2. Keyword fields without specifying an analyzer

Regardless of whether analyze_wildcard is set to true or false, the query is case-sensitive:

json
// The results of the following two queries are the same, both only matching case exactly
{
  "query_string": {
    "query": "email:Te*",
    "analyze_wildcard": true
  }
}

{
  "query_string": {
    "query": "email:Te*",
    "analyze_wildcard": false
  }
}

3. Contradictory behavior when specifying an analyzer for Keyword fields

When analyzer: "standard" is specified for a keyword field, a phenomenon inconsistent with the official documentation appears (or perhaps my understanding of "full analysis" vs. "normalization" is incorrect):

json
// Leading or middle wildcard: Converts to lowercase (matches "normalization" description)
// Actual query: *te*
{
  "query_string": {
    "query": "email:(*Te*)",
    "analyze_wildcard": true,
    "analyzer": "standard"
  }
}

// Trailing wildcard: Does not convert to lowercase (contradicts "full analysis" description)
// Actual query: Te*
{
  "query_string": {
    "query": "email:(Te*)",
    "analyze_wildcard": true,
    "analyzer": "standard"
  }
}

According to the official documentation, a trailing wildcard should undergo "full analysis"; theoretically, Te* should be converted to te* by the standard analyzer, but the test result shows it remains Te*.

Processing Differences by Wildcard Position

Wildcard PatternOfficial Description of ProcessingKeyword + standard analyzer Test Result
Te*Full analysisNo lowercase conversion (Te*)
*Te*Normalization onlyLowercase conversion (*te*)
*TeNormalization onlyLowercase conversion (*te)
T*eNormalization onlyLowercase conversion (t*e)

4. auto_generate_synonyms_phrase_query

Controls how synonyms are handled:

  • true (default): Automatically generates phrase queries for synonyms, preserving word order and adjacency.
  • false: Generates only standard synonym queries, ignoring word order.

For example, if "ny" and "new york" are set as synonyms:

json
{
  "query_string": {
    "query": "ny restaurants",
    "auto_generate_synonyms_phrase_query": true
  }
}
  • true: Matches "ny restaurants" or "new york restaurants" ("new york" as a whole phrase).
  • false: Matches "ny restaurants" or "new restaurants" or "york restaurants".

5. Weight Control: boost and Field Weighting

Elasticsearch provides two levels of weight control mechanisms:

5.1 Field Boost

Use the ^ syntax to adjust the weight of specific fields.

json
{
  "query_string": {
    "query": "apple iphone",
    "fields": ["title^3", "description^2", "content"]
  }
}
  • Function: Controls the relative importance of different fields in the same query.
  • Mechanism:
    • Each field independently calculates a base score (based on the BM25 algorithm).
    • The score for the title field is multiplied by 3.
    • The score for the description field is multiplied by 2.
    • The score for the content field is multiplied by 1 (default).
    • Finally, all weighted field scores are added together to get the final score.
  • Important Note: title^3 does not mean the final score of title is 3 times that of content, but rather that the base score of the title field is amplified by 3 before being combined with other fields. The final score is also affected by factors like term frequency, inverse document frequency, and document length.
  • Scenario: When searching multiple fields, some fields (like titles) are more representative of the document topic than others (like content).

Calculation Example (base scores are hypothetical):

Assuming searching for "apple", the base scores for each field are as follows:

FieldBase ScoreWeighted Score
title2.02.0 × 3 = 6.0
description1.51.5 × 2 = 3.0
content2.52.5 × 1 = 2.5
Final Score11.5

Note: The base scores above are hypothetical examples used to explain the calculation logic. Actual scores vary based on index state, document content, term frequency, etc.; use the _explain API to view the actual scoring process.


5.2 Query Boost

Adjusts the weight of the entire query clause.

json
{
  "query_string": {
    "query": "apple iphone",
    "boost": 2.0
  }
}
  • Function: Adjusts the importance of an entire query clause in a compound query (like a bool query).
  • Important Limitation: If used alone, the boost parameter has no effect on sorting (all document scores are multiplied by the same factor, so the relative order does not change).
  • Primary Use:
    • In the should clause of a bool query, adjust the relative importance of different query conditions.
    • Make certain matching conditions have a greater impact on the final sorting than others.
    • Reflect the importance differences of different search dimensions in business logic.
  • Scenario: Combining multiple query methods (text search, exact match, range query, etc.) where you need to adjust their impact weight on the final sorting.

5.3 Combining Both

Example

json
{
  "query": {
    "bool": {
      "should": [
        {
          "query_string": {
            "query": "apple",
            "fields": ["title^2"],
            "boost": 2.0
          }
        },
        {
          "query_string": {
            "query": "iphone",
            "fields": ["description"],
            "boost": 4.0
          }
        }
      ]
    }
  }
}

Calculation Explanation (base scores are hypothetical):

Assuming there are three documents:

Documenttitle contains "apple"description contains "iphone"Score Calculation
Doc A✅ (Base 3.0)✅ (Base 2.0)(3.0 × 2 × 2.0) + (2.0 × 1 × 4.0) = 20.0
Doc B✅ (Base 2.5)(2.5 × 2 × 2.0) + 0 = 10.0
Doc C✅ (Base 2.5)0 + (2.5 × 1 × 4.0) = 10.0

Sorting Result: Doc A (20.0) > Doc B (10.0) = Doc C (10.0)

Analysis:

  • Doc A matches both conditions and gets the highest score.
  • Doc B only matches "apple" in the title: Base score 2.5 × Field boost 2 × Query boost 2.0 = 10.0.
  • Doc C only matches "iphone" in the description: Base score 2.5 × Field boost 1 × Query boost 4.0 = 10.0.

Even though Doc C's query boost (4.0) is higher than Doc B's (2.0), because Doc B has a field boost (^2), the actual result still depends on the base scores.

Note: The base scores above are hypothetical; actual scores must be viewed using the _explain API.


5.4 Key Differences

FeatureField Boost (^)Query Boost (boost)
ScopeDifferent fields within a single queryDifferent query clauses in a compound query
Control ObjectRelative weight between fieldsRelative weight between query clauses
Usage LocationInside the fields parameterTop-level parameter of the query clause
Used AloneEffective (affects field score combination)Ineffective (does not change sorting)
Typical ScenarioTitle is more important than contentUser search is more important than filter conditions

6. Fuzzy Search (fuzziness and phrase_slop)

The tilde ~ has two different meanings in QueryString, depending on its position:

6.1 Fuzzy Search (Tilde after a word)

text
apple~    // Tilde after a word indicates fuzzy search
apple~2   // Specifies fuzziness as 2
  • Corresponding parameter: fuzziness.
  • Function: Handles spelling errors for a single word based on edit distance.
  • Identification: Used after a word.

Limitations on fuzziness values:

  • Valid values: 0, 1, 2, or "AUTO".
  • Values greater than 2 cause an error: Valid edit distances are [0, 1, 2].

Conditions for fuzziness parameter to take effect:

The fuzziness parameter only takes effect when a word in the query string uses ~ (without a specified number):

json
// ✅ Word has ~, no number, no fuzziness set: default fuzziness is 1
{
  "query_string": {
    "query": "apple~"  // apple uses fuzziness 1 (default)
  }
}

// ✅ Word has ~, no number: uses fuzziness parameter
{
  "query_string": {
    "query": "apple~",
    "fuzziness": 2  // Takes effect, apple uses fuzziness 2
  }
}

// ❌ Word has no ~: does not take effect
{
  "query_string": {
    "query": "apple banana",
    "fuzziness": 1  // Does not take effect, both words are exact matches
  }
}

// ❌ Word has ~N (explicit number): uses the number in the query string
{
  "query_string": {
    "query": "apple~2",
    "fuzziness": 1  // Does not take effect, uses the 2 in the query string
  }
}

// ⚠️ Mixed case: only words with ~ apply fuzzy search
{
  "query_string": {
    "query": "apple~2 banana",
    "fuzziness": 1  // Does not take effect, apple uses 2, banana is exact match
  }
}

{
  "query_string": {
    "query": "apple~ banana",
    "fuzziness": 1  // Only takes effect for apple (fuzziness 1), banana is exact match
  }
}

Priority Rules:

  1. ~N in the query string (explicit number): Uses that number directly.
  2. ~ in the query string (no number) + fuzziness parameter: Uses the fuzziness parameter value.
  3. ~ in the query string (no number) + fuzziness not set: Default fuzziness is 1.
  4. No ~ in the query string: The word is an exact match; the fuzziness parameter does not take effect.

⚠️ Important Note:

The fuzziness parameter must be used with ~ in the query string to take effect. If there is no ~ after the word, the word is treated as an exact match, regardless of the fuzziness parameter setting.

Fuzziness setting differences:

  • "fuzziness": "AUTO": Automatically adjusts based on word length. Default behavior is equivalent to AUTO:3,6, with rules:
    • Word length 0-2 characters: fuzziness = 0 (must be exact match)
    • Word length 3-5 characters: fuzziness = 1
    • Word length 6+ characters: fuzziness = 2
  • "fuzziness": "AUTO:[low],[high]": AUTO mode with custom thresholds. For example, AUTO:4,7 means:
    • Word length 0-3 characters: fuzziness = 0
    • Word length 4-6 characters: fuzziness = 1
    • Word length 7+ characters: fuzziness = 2
  • "fuzziness": 1 or "fuzziness": 2: Fixed maximum allowed edit distance.

For detailed explanations, refer to the official documentation.

Example:

  • apple~1 can match spelling errors like "aple", "appla", etc.

6.2 Proximity Search (Tilde after a phrase)

text
"apple banana"~5  // Tilde after a phrase indicates proximity search
  • Corresponding parameter: phrase_slop
  • Function: Handles the order and distance of words in a phrase.
  • Identification: Used after a phrase enclosed in quotes.

Slop value calculation logic:

Slop represents the minimum number of "moves" required for words, which can handle:

  1. Words interspersed with other words.
  2. Incorrect word order (swapped).

Calculation explanation:

Assuming the index contains "quick brown fox jumps"

text
// Example 1: Interspersed words
Query: "quick fox"
Index: "quick brown fox"
→ "fox" needs to move 1 step to the left, skipping "brown"
→ slop = 1

// Example 2: Adjacent word order swapped
Query: "brown quick"
Index: "quick brown"
→ Two words swap positions
→ slop = 2 (official documentation: swap cost is 2)

// Example 3: Non-adjacent word order swapped + interspersed
Query: "fox quick"
Index: "quick brown fox"
→ "fox" needs to move to before "quick", crossing 2 positions
→ slop = 3

Actual Example:

json
// slop = 0: Must match exactly
{
  "query_string": {
    "query": "\"quick brown\""
  }
}

// ✅ Matches: "quick brown fox"
// slop = 1: Allows 1 word in between
{
  "query_string": {
    "query": "\"quick fox\"~1"
  }
}

// slop = 2: Allows adjacent words to be swapped
// ✅ Matches: "quick brown fox"
// ❌ Does not match: "quick fox"
{
  "query_string": {
    "query": "\"brown quick\"~2"
  }
}

// slop = 3: Allows more complex moves
// ✅ Matches: "quick brown fox"
{
  "query_string": {
    "query": "\"fox quick\"~3"
  }
}

Setting in API:

json
{
  "query_string": {
    "query": "apple~2 \"quick fox\"~3",
    "fuzziness": "AUTO",  // Global setting, overridden by specific values in the query
    "phrase_slop": 2      // Global setting, overridden by specific values in the query
  }
}

Priority:

Values set using ~ in the query string override the global settings in the API parameters.

Pagination and Sorting

Pagination Parameters

json
{
  "query": {
    "query_string": {
      "query": "apple"
    }
  },
  "from": 0,   // Starting position, defaults to 0
  "size": 10   // Number of items per page, defaults to 10
}
  • from: Specifies which result to start returning from (0 represents the first result).
  • size: Specifies how many results to return.

Notes:

  • Deep pagination (from + size too large) affects performance.
  • Elasticsearch defaults to limiting from + size to no more than 10,000.
  • If you need to process large amounts of data, it is recommended to use the Search After or Scroll API.

Sorting Parameters

The sort parameter accepts an array, allowing you to specify multiple sorting conditions; the sorting priority is determined by the array order.

Sorting Syntax

Method 1: Simple field name (default ascending)

json
{
  "sort": ["price"]  // Sort by price ascending
}

Method 2: Field + sort direction object

json
{
  "sort": [
    { "price": "asc" }   // Sort by price ascending
  ]
}

Method 3: Full configuration object

json
{
  "sort": [
    {
      "price": {
        "order": "desc",           // Sort direction: asc (ascending) or desc (descending)
        "missing": "_last"         // Documents missing this field are placed last
      }
    }
  ]
}

Multi-field Sorting

json
{
  "query": {
    "query_string": {
      "query": "apple"
    }
  },
  "sort": [
    { "price": "asc" },      // First priority: sort by price ascending
    { "created_at": "desc" }, // Second priority: sort by creation time descending if prices are equal
    "_score"                  // Third priority: sort by relevance score if other conditions are equal
  ]
}

Special Sorting Values

  • "_score": Sort by query relevance score (defaults to descending).
  • "_doc": Sort by the internal order of documents (fastest, but order is not fixed).

Sorting Direction

  • "asc": Ascending - from small to large.
  • "desc": Descending - from large to small.

Handling Missing Values

Use the missing parameter to specify where documents missing the sort field should be placed:

json
{
  "sort": [
    {
      "price": {
        "order": "asc",
        "missing": "_last"   // Options: _first (place first), _last (place last), or specify a default value
      }
    }
  ]
}

Full Example

json
{
  "query": {
    "query_string": {
      "query": "laptop"
    }
  },
  "from": 0,
  "size": 20,
  "sort": [
    { "price": { "order": "asc", "missing": "_last" } },
    { "rating": "desc" },
    "_score"
  ]
}

Sorting Logic Explanation:

  1. Sort by price ascending first (those without a price are placed last).
  2. If prices are equal, sort by rating descending.
  3. If prices and ratings are both equal, sort by relevance score.

Special Character Escaping

Many special characters in QueryString have specific meanings. To use them as ordinary characters, they need to be escaped with a backslash \:

text
\+ \- \= \&\& \|\| \> \< \! \( \) \{ \} \[ \] \^ \" \~ \* \? \: \\ \/

For example:

  • Search for documents containing a plus sign: title:\+1.
  • Search for documents containing parentheses: content:\(sample\).
  • Search for documents containing quotes: description:\"quoted text\".

Change Log

  • 2025-04-13 Initial document creation.
  • 2025-10-03
    • Refined phrasing and unified terminology.
    • Corrected explanation of date query range syntax (date fields do not support comparison operators; range query syntax should be used).
    • Corrected the omission of field base scores in weight calculation.
    • Added technical details.